package com.key.puzzlemodel.view

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import androidx.core.view.MotionEventCompat


/**
 *
 * @功能描述:     滑动,双指缩放的view
 * @创建时间:     2022/1/4
 * @创建者:       阳
 * @修改时间:     2022/1/4
 * @修改者:       阳
 */
class DragScaleView : View {
    //监听图片缩放
    private var mScaleDetector: ScaleGestureDetector? = null

    //监听图片移动
    private var mGestureDetector: GestureDetector? = null

    //当前的缩放比例
    private var mScaleFactor = 1.0f

    constructor(context: Context?) : super(context) {}
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(context)
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
    }

    private fun init(context: Context) {
        mScaleDetector = ScaleGestureDetector(context, SimpleScaleListenerImpl())
        mGestureDetector = GestureDetector(context, SimpleGestureListenerImpl())
    }

    private val bmpPaint = Paint()

    //图片资源
    private var bmp: Bitmap? = null

    //图片的宽高
    private var bmpWidth = 0
    private var bmpHeight = 0
//    fun setImageResource(id: Int) {
//        bmp = BitmapFactory.decodeResource(resources, id)
//        bmpWidth = bmp.getWidth()
//        bmpHeight = bmp.getHeight()
//        initViewSize()
//        invalidate()
//    }

    fun setImageBimap(bitmap: Bitmap) {
        bmp = bitmap
        bmpWidth = bitmap.width
        bmpHeight = bitmap.height
        initViewSize()
        invalidate()
    }

    //绘制图片的起始位置
    private var mPosX = 0f
    private var mPosY = 0f
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (bmp == null) {
            return
        }
        if (!hasGetViewSize) {
            initViewSize()
        }
        canvas.save()
        checkBounds()
        //以图片的中心为基点进行缩放
        canvas.scale(mScaleFactor, mScaleFactor, mPosX + bmpWidth / 2, mPosY + bmpHeight / 2)
        canvas.drawBitmap(bmp!!, mPosX, mPosY, bmpPaint)
        canvas.restore()
    }


    private var lastX: Float = 0f
    private var lastY: Float = 0f
    private val INVALID_POINTER_ID = -1
    private var mActivePointerId = INVALID_POINTER_ID
    override fun onTouchEvent(event: MotionEvent): Boolean {
        //双指缩放
        mScaleDetector!!.onTouchEvent(event)
        //单指移动
        mGestureDetector!!.onTouchEvent(event)
        return true

        //也可以自己实现“单指移动图片”
        /*
        int action = MotionEventCompat.getActionMasked(event);
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                final int pointerIndex = MotionEventCompat.getActionIndex(event);
                mActivePointerId = MotionEventCompat.getPointerId(event, pointerIndex);
                lastX = event.getX();
                lastY = event.getY();
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                // Find the index of the active pointer and fetch its position
                final int pointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId);
                float currentX = MotionEventCompat.getX(event, pointerIndex);
                float currentY = MotionEventCompat.getY(event, pointerIndex);
                mPosX += (currentX - lastX);
                mPosY += (currentY - lastY);
                invalidate();
                lastX = currentX;
                lastY = currentY;
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = MotionEventCompat.getActionIndex(event);
                final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    lastX = MotionEventCompat.getX(event, newPointerIndex);
                    lastY = MotionEventCompat.getY(event, newPointerIndex);
                    mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }
        }
        */

        val action = MotionEventCompat.getActionMasked(event)
        when (action) {
            MotionEvent.ACTION_DOWN -> {
                val pointerIndex = MotionEventCompat.getActionIndex(event)
                mActivePointerId = MotionEventCompat.getPointerId(event, pointerIndex)
                lastX = event.x
                lastY = event.y
            }
            MotionEvent.ACTION_MOVE -> {

                // Find the index of the active pointer and fetch its position
                val pointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId)
                val currentX = MotionEventCompat.getX(event, pointerIndex)
                val currentY = MotionEventCompat.getY(event, pointerIndex)
                mPosX += currentX - lastX
                mPosY += currentY - lastY
                invalidate()
                lastX = currentX
                lastY = currentY
            }
            MotionEvent.ACTION_POINTER_UP -> {
                val pointerIndex = MotionEventCompat.getActionIndex(event)
                val pointerId = MotionEventCompat.getPointerId(event, pointerIndex)
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    val newPointerIndex = if (pointerIndex == 0) 1 else 0
                    lastX = MotionEventCompat.getX(event, newPointerIndex)
                    lastY = MotionEventCompat.getY(event, newPointerIndex)
                    mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex)
                }
            }
            MotionEvent.ACTION_UP -> {
                mActivePointerId = INVALID_POINTER_ID
            }
        }
    }

    /**
     * 不能超出边界.
     * 原则是：图片较小时任意一条边都不能出了边界，图片较大任意一条边都不能进入边界。宽度和高度分别独立计算。
     */
    private fun checkBounds() {
        if (mScaleFactor > widthScale) {
            //宽度方向已经填满
            mPosX = Math.min(mPosX, (mScaleFactor - 1) * (bmpWidth / 2))
            mPosX = Math.max(mPosX, viewWidth - bmpWidth - (mScaleFactor - 1) * (bmpWidth / 2))
        } else {
            mPosX = Math.max(mPosX, (mScaleFactor - 1) * (bmpWidth / 2))
            mPosX = Math.min(mPosX, viewWidth - bmpWidth - (mScaleFactor - 1) * (bmpWidth / 2))
        }
        if (mScaleFactor > heightScale) {
            //高度方向已经填满
            mPosY = Math.min(mPosY, (mScaleFactor - 1) * (bmpHeight / 2))
            mPosY = Math.max(mPosY, viewHeight - bmpHeight - (mScaleFactor - 1) * (bmpHeight / 2))
        } else {
            mPosY = Math.max(mPosY, (mScaleFactor - 1) * (bmpHeight / 2))
            mPosY = Math.min(mPosY, viewHeight - bmpHeight - (mScaleFactor - 1) * (bmpHeight / 2))
        }
    }

    private var viewWidth = 0
    private var viewHeight = 0

    //组件尺寸只需要获取一次
    private var hasGetViewSize = false
    private fun initViewSize() {
        viewWidth = width
        viewHeight = height
        if (viewWidth > 0 && viewHeight > 0) {
            hasGetViewSize = true
            widthScale = 1.0f * viewWidth / bmpWidth
            heightScale = 1.0f * viewHeight / bmpHeight
            //初始缩放比例（使组件刚好铺满）
            mScaleFactor = Math.min(widthScale, heightScale)

            //初始时图片居中绘制
            mPosX = (viewWidth / 2 - bmpWidth / 2).toFloat()
            mPosY = (viewHeight / 2 - bmpHeight / 2).toFloat()
        }
    }

    /**
     * 宽度和高度放大多少倍时，刚好填满此方向的屏幕
     */
    private var widthScale = 0f
    private var heightScale = 0f

    //缩放
    private inner class SimpleScaleListenerImpl :
        ScaleGestureDetector.SimpleOnScaleGestureListener() {
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            mScaleFactor *= detector.scaleFactor
            //缩放倍数范围：0.3～3
            mScaleFactor = Math.max(0.3f, Math.min(mScaleFactor, 3.0f))
            invalidate()
            return true
        }
    }

    //移动
    private inner class SimpleGestureListenerImpl : GestureDetector.SimpleOnGestureListener() {
        override fun onScroll(
            e1: MotionEvent,
            e2: MotionEvent,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            mPosX -= distanceX
            mPosY -= distanceY
            invalidate()
            return true
        }
    }
}